package enum

import (
	"errors"
	"fmt"
	"math"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"yunj/pkg/yunj/util"
)

type EnumInterface[T comparable] interface {
	AllConstAttrs() map[T]map[string]any
	GetValue() T
	GetAttrMap(key string) map[T]any
	GetDescMap() map[T]string
	GetAttr(attr string) any
	GetStrAttr(attr string) string
	GetDesc() string
	GetColor() string
	GetSortConsts() []T
	GetCommaSepConstStr() string
	IsValue(value any) (val T, ok bool)
}

// T 不自定义类型，防止数据库占位符?替换为字符串，在mysql进行匹配时发生类型转换
// comparable 可比较类型
type Enum[T comparable] struct {
	Value     T
	ErrPrefix string // 错误前缀
	Err       error  // 错误

	enumInstance EnumInterface[T]
}

// 设置枚举实例
func SetEnumInstance[T comparable](e *Enum[T], enumInstance EnumInterface[T], value ...T) {
	e.enumInstance = enumInstance

	// 获取指针的反射值
	enumInstanceValue := reflect.ValueOf(e.enumInstance)
	// 检查传入的是否为指针
	if enumInstanceValue.Kind() != reflect.Ptr || enumInstanceValue.IsNil() {
		e.SetError("请传入枚举实例指针值！")
	}
	// 设置值
	if len(value) > 0 {
		e.SetValue(value[0])
	}
}

// 获取构建器实例的错误前缀
func (e *Enum[T]) getErrPrefix() (prefix string, err error) {
	err = e.GetError()
	if err != nil {
		return
	}
	prefix = e.ErrPrefix
	return
}

// 设置构建器实例的错误前缀
func (e *Enum[T]) setErrPrefix(prefix string) (err error) {
	err = e.GetError()
	if err != nil {
		return
	}
	e.ErrPrefix = prefix
	return
}

// 获取枚举错误
func (e *Enum[T]) GetError() error {
	return e.Err
}

// 设置枚举错误
func (e *Enum[T]) SetError(err any) error {
	if _err := e.GetError(); _err != nil {
		return _err
	}
	var resErrMsg string
	if _errMsg, ok := err.(string); ok {
		resErrMsg = _errMsg
	} else if _err, ok := err.(error); ok {
		resErrMsg = _err.Error()
	} else {
		resErrMsg = "未知错误！"
	}

	// 错误前缀
	errPrefix, _ := e.getErrPrefix()
	if errPrefix == "" {
		typ := util.PackageFullName(e.enumInstance) + "." + util.TypeName(e.enumInstance)
		errPrefix = "枚举" + typ
		e.setErrPrefix(errPrefix)
	}

	if !strings.HasPrefix(resErrMsg, errPrefix) {
		resErrMsg = errPrefix + resErrMsg
	}
	newErr := errors.New(resErrMsg)
	e.Err = newErr
	return newErr
}

func (e *Enum[T]) GetValue() T {
	return e.Value
}

func (e *Enum[T]) SetValue(value T) {
	e.Value = value
}

// 获取所有枚举值的指定属性值
func (e *Enum[T]) GetAttrMap(key string) map[T]any {
	res := map[T]any{}
	allConstAttrs := e.enumInstance.AllConstAttrs()
	for enumVal, attrs := range allConstAttrs {
		if attr, exists := attrs[key]; exists {
			res[enumVal] = attr
		}
	}
	return res
}

// 获取所有枚举值对应的描述
func (e *Enum[T]) GetDescMap() map[T]string {
	res := map[T]string{}
	attrMap := e.GetAttrMap("desc")
	for k, v := range attrMap {
		if desc, ok := v.(string); ok {
			res[k] = desc
		}
	}
	return res
}

// 获取某一属性值
func (e *Enum[T]) GetAttr(attr string) any {
	allConstAttrs := e.enumInstance.AllConstAttrs()
	enumAttrs, exists := allConstAttrs[e.GetValue()]
	if !exists {
		return nil
	}
	attrValue, exists := enumAttrs[attr]
	if !exists {
		return nil
	}
	return attrValue
}

// 获取某一属性的字符串值
func (e *Enum[T]) GetStrAttr(attr string) string {
	raw := e.GetAttr(attr)
	res, _ := ToString(raw)
	return res
}

// 获取描述值
func (e *Enum[T]) GetDesc() string {
	return e.GetStrAttr("desc")
}

// 获取颜色
func (e *Enum[T]) GetColor() string {
	return e.GetStrAttr("color")
}

// 获取排序后的常量值
func (e *Enum[T]) GetSortConsts() []T {
	allConstAttrs := e.enumInstance.AllConstAttrs()

	// 提取所有的枚举值
	enumValues := make([]T, 0, len(allConstAttrs))
	enumValueSorts := map[T]int{}
	sortKeyExists := true
	for enumValue, enumAttrs := range allConstAttrs {
		enumValues = append(enumValues, enumValue)
		if sortKeyExists {
			sortRaw, exists := enumAttrs["sort"]
			if !exists {
				sortKeyExists = false
				continue
			}
			sort, ok := sortRaw.(int)
			if !ok {
				sortKeyExists = false
				continue
			}
			enumValueSorts[enumValue] = sort
		}
	}

	// 排序
	sort.Slice(enumValues, func(i, j int) bool {
		return enumValueSorts[enumValues[i]] < enumValueSorts[enumValues[j]]
	})

	return enumValues
}

// 获取逗号分隔常量的字符串值
func (e *Enum[T]) GetCommaSepConstStr() string {
	allConstAttrs := e.enumInstance.AllConstAttrs()
	var str string
	for k := range allConstAttrs {
		value, _ := ToString(k)
		if str != "" {
			str += "," + value
		} else {
			str = value
		}
	}
	return str
}

// 判断是否为枚举值val
func (e *Enum[T]) IsValue(value any) (val T, ok bool) {
	var err error
	if _, isUint8 := any(val).(uint8); isUint8 {
		if value, err = ToUint8(value); err != nil {
			return
		}
	} else if _, isStr := any(val).(string); isStr {
		if value, err = ToString(value); err != nil {
			return
		}
	} else if _, isInt := any(val).(int); isInt {
		if value, err = ToInt(value); err != nil {
			return
		}
	} else {
		// 其他类型直接断言
		if _, ok = value.(T); !ok {
			return
		}
	}
	val = value.(T) // 将值转换为 T 类型
	allConstAttrs := e.enumInstance.AllConstAttrs()
	_, ok = allConstAttrs[val]
	return
}

// 其他类型转换为字符串
func ToString(value any) (string, error) {
	// 使用反射来判断值的类型，并相应地转换为字符串
	v := reflect.ValueOf(value)
	if !v.IsValid() {
		return "", nil
	}
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(v.Uint(), 10), nil
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
	case reflect.Bool:
		return strconv.FormatBool(v.Bool()), nil
	case reflect.String:
		return v.String(), nil
	// 根据需要添加更多的类型处理
	default:
		return "", fmt.Errorf("string类型转换，不支持类型： %s", v.Type())
	}
}

// 将不同类型的值转换为 int 类型
func ToInt(value interface{}) (int, error) {
	v := reflect.ValueOf(value)
	if !v.IsValid() {
		return 0, nil
	}
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return int(v.Int()), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return int(v.Uint()), nil
	case reflect.Float32, reflect.Float64:
		return int(v.Float()), nil
	case reflect.String:
		return strconv.Atoi(v.String())
	case reflect.Bool:
		if v.Bool() {
			return 1, nil
		}
		return 0, nil
	default:
		return 0, fmt.Errorf("int类型转换，不支持类型: %T", value)
	}
}

// 严格转换为 uint8，拒绝非零小数位（整数或整数型字符串）
func ToUint8(value interface{}) (uint8, error) {
	errPrefix := "uint8类型转换"
	v := reflect.ValueOf(value)
	if !v.IsValid() {
		return 0, nil
	}
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		val := v.Int()
		if val < 0 || val > math.MaxUint8 {
			return 0, fmt.Errorf("%s，整数 %d 超出 uint8 范围 [0, 255]", errPrefix, val)
		}
		return uint8(val), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		val := v.Uint()
		if val > math.MaxUint8 {
			return 0, fmt.Errorf("%s，无符号整数 %d 超出范围", errPrefix, val)
		}
		return uint8(val), nil
	case reflect.Float32, reflect.Float64:
		val := v.Float()
		if val != math.Trunc(val) { // 检查小数位是否为 0
			return 0, fmt.Errorf("%s，浮点数 %f 包含非零小数位", errPrefix, val)
		}
		valInt := int(val)
		if valInt < 0 || valInt > math.MaxUint8 {
			return 0, fmt.Errorf("%s，浮点数 %f 超出范围", errPrefix, val)
		}
		return uint8(valInt), nil
	case reflect.String:
		val := v.String()
		s := strings.TrimSpace(val)
		// 处理包含全是 0 的小数位的情况
		if strings.Contains(s, ".") {
			parts := strings.Split(s, ".")
			if len(parts) == 2 && strings.TrimLeft(parts[1], "0") == "" {
				s = parts[0]
			} else {
				return 0, fmt.Errorf("%s，字符串 '%s' 包含非零小数位", errPrefix, s)
			}
		}
		if strings.ContainsAny(s, "eE") {
			return 0, fmt.Errorf("%s，字符串 '%s' 包含指数", errPrefix, s)
		}
		num, err := strconv.ParseUint(s, 10, 8)
		if err != nil {
			return 0, fmt.Errorf("%s，字符串 '%s' 非有效整数: %w", errPrefix, s, err)
		}
		return uint8(num), nil
	case reflect.Bool:
		if v.Bool() {
			return 1, nil
		}
		return 0, nil
	default:
		return 0, fmt.Errorf("%s，不支持类型: %T", errPrefix, value)
	}
}
